package org.smart4j.framework.common.helper;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.smart4j.framework.common.bean.FileParam;
import org.smart4j.framework.common.bean.FormParam;
import org.smart4j.framework.common.bean.Param;
import org.smart4j.framework.common.util.CodecUtil;
import org.smart4j.framework.common.util.FileUtil;
import org.smart4j.framework.common.util.StreamUtil;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 文件上传工具类
 *
 * @author YooLin1c
 * @version 1.0.0
 * @since 2018-02-07 19:06
 */
@Slf4j
public final class UploadHelper {
    /**
     * Apache Commons FileUpload提供的Servlet文件上传对象
     */
    private static ServletFileUpload servletFileUpload;

    public static void init(ServletContext servletContext) {
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        servletFileUpload = new ServletFileUpload(
                new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, repository));
        servletFileUpload.setFileSizeMax(ConfigHelper.getDefaultFileSizeThreshold() * FileUtils.ONE_MB);
    }

    public static boolean isMultipart(HttpServletRequest request) {
        return ServletFileUpload.isMultipartContent(request);
    }

    public static Optional<Param> getParam(HttpServletRequest request) {
        List<FormParam> formParamList = new ArrayList<>();
        List<FileParam> fileParamList = new ArrayList<>();
        try {
            Map<String, List<FileItem>> parameterMap = servletFileUpload.parseParameterMap(request);
            if (MapUtils.isEmpty(parameterMap)) {
                return Optional.empty();
            }
            for (Map.Entry<String, List<FileItem>> parameterEntry : parameterMap.entrySet()) {
                String parameterName = parameterEntry.getKey();
                List<FileItem> fileItems = parameterEntry.getValue();
                if (CollectionUtils.isEmpty(fileItems)) {
                    continue;
                }
                for (FileItem fileItem : fileItems) {
                    if (fileItem.isFormField()) {
                        String parameterValue = fileItem.getString("UTF-8");
                        formParamList.add(new FormParam(parameterName, parameterValue));
                    } else {
                        FileParam fileParam = new FileParam();
                        fileParam.setFieldName(parameterName);
                        if (StringUtils.isBlank(parameterName)) {
                            log.warn("[fieldName:{}] upload file failed because the file need a name!", parameterName);
                            continue;
                        }
                        fileParam.setFileName(FileUtil.getRealFileName(
                                new String(fileItem.getName().getBytes(), "UTF-8")));
                        fileParam.setContentType(fileItem.getContentType());
                        fileParam.setFileSize(fileItem.getSize());
                        fileParam.setFieldValue(fileItem.getInputStream());
                        fileParamList.add(fileParam);
                    }
                }
            }
        } catch (Exception e) {
            log.error("create param failed!", e);
            throw new RuntimeException(e);
        }
        return Optional.of(new Param(formParamList, fileParamList));
    }

    public static void uploadFile(String basePath, FileParam... fileParams) {
        if (ArrayUtils.isEmpty(fileParams)) {
            log.warn("there is no file need to upload!");
            return;
        }
        try {
            for (FileParam fileParam : fileParams) {
                String filePath = basePath.concat(fileParam.getFieldName());
                FileUtils.copyInputStreamToFile(fileParam.getFieldValue(), FileUtil.createFile(filePath));
            }
        } catch (Exception e) {
            log.error("upload file failed!", e);
            throw new RuntimeException(e);
        }
    }
}
